#include <cstring>
#include <algorithm>
#include <cstring>
#include <cstdio>

using std::swap;


//------------------------------------------------------------------------------

template<class ParameterClass>
ParameterClass* ClassParameter::findParameterTemplate(const char* n) const {
  vector<Parameter*>::const_iterator pIter = subAsgn.begin();
  for (;pIter!=subAsgn.end();++pIter) {
    if (strcmp(n,(*pIter)->getName()) == 0) return dynamic_cast<ParameterClass*>(*pIter);
  }
  return NULL;
}

//------------------------------------------------------------------------------

template<class ParameterClass>
ParameterClass& ClassParameter::getParameterTemplate(const char* n) const {
  ParameterClass* obj = findParameterTemplate<ParameterClass>(n);
  if (obj == NULL) throw;
  return *obj;
}

//------------------------------------------------------------------------------

template<class T>
ListParameter<T>::ListParameter(const char* n,int m) : Parameter(n,m) {
}

//------------------------------------------------------------------------------

template<class T>
ListParameter<T>::ListParameter(const ListParameter<T>& a) : Parameter(a) {
  for (size_t i=0; i<a.val.size(); ++i) val.push_back(a.val[i]);
}

//------------------------------------------------------------------------------

template<class T>
ListParameter<T>::~ListParameter() {
}

//------------------------------------------------------------------------------

template<class T>
Parameter* ListParameter<T>::duplicate() const {
  return new ListParameter<T>(*this);
}

//------------------------------------------------------------------------------

template<class T>
void ListParameter<T>::addToList(const char* text) {
  fprintf(stderr, "Error: '%s' has no addToList function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<int>::addToList(const char* text) {
  val.push_back(atoi(text));
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<double>::addToList(const char* text) {
  val.push_back(atof(text));
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<string>::addToList(const char* text) {
  val.push_back(string(text+1, strlen(text)-2)); // remove the double quotes
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<pair<int,int> >::addToList(const char* text) {
  // removing the colon to ease the parsing
  size_t len = strlen(text);
  char* arg = new char[len+1];
  strcpy(arg, text);
  size_t i;
  for (i=0; i<len; ++i) {
    if (arg[i] == ':') arg[i] = ' ';
  }
  // scanning for one integer or a couple of integers
  pair<int,int> p;
  size_t pos = 1;
  i = 0;
  do {
    if (arg[i] == ' ') {
      ++i;
    } else {
      char str[256];
      sscanf(arg+i, "%s", str);
      if (pos == 1) {
        p.first = atoi(str);
        p.second = p.first;
        ++pos;
      }
      else if (pos == 2) {
        p.second = atoi(str);
        if (p.first > p.second) swap(p.first, p.second);
      }
      else {
        fprintf(stderr, "Error: wrong syntax for pair '%s'\n", text);
        exit(1);
      }
      i += strlen(str);
    }
  } while (i < len);
  if (arg) delete [] arg;
  // checking whether the pair can be added
  for (i=0; i<val.size(); ++i) {
    int first = val[i].first;
    int second = val[i].second;
    if (p.first >= first && p.second <= second) {
      return;
    }
    else if (p.first < first && p.second > second) {
      val[i].first = p.first;
      val[i].second = p.second;
      return;
    }
    else if ((p.first >= first && p.first <= second) && p.second > second) {
      val[i].second = p.second;
      return;
    }
    else if ((p.second >= first && p.second <= second) && p.first < first) {
      val[i].first = p.first;
      return;
    }
    else if (p.first == second+1) {
      val[i].second = p.second;
      return;
    }
    else if (p.second == first-1) {
      val[i].first = p.first;
      return;
    }
  }
  val.push_back(p);
}

//------------------------------------------------------------------------------

template<class T>
string ListParameter<T>::convertToString(const T& t) const {
  fprintf(stderr, "Error: '%s' has no convertToString function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
string ListParameter<int>::convertToString(const int& t) const {
  char s[256];
  sprintf(s, "%d", t);
  return string(s);
}

//------------------------------------------------------------------------------

template<>
inline
string ListParameter<double>::convertToString(const double& t) const {
  char s[256];
  sprintf(s, "%e", t);
  return string(s);
}

//------------------------------------------------------------------------------

template<>
inline
string ListParameter<string>::convertToString(const string& t) const {
  string s;
  s += "\""; s += t; s += "\""; // add the double quotes
  return s;
}

//------------------------------------------------------------------------------

template<>
inline
string ListParameter<pair<int,int> >::convertToString(const pair<int,int>& t) const {
  char s[256];
  if (t.first == t.second) sprintf(s, "%d", t.first);
  else sprintf(s, "%d:%d", t.first, t.second);
  return string(s);
}

//------------------------------------------------------------------------------

template<class T>
void ListParameter<T>::assignList(const char* line) {
  
  if (isActive()) {
    val.resize(0);
    if (line[0] == 0) return;
    int lline = strlen(line);
    int i = 0;
    do {
      if (line[i] == ' ') {
        ++i;
      } else {
        char str[256];
        sscanf(line+i, "%s", str);
        addToList(str);
        i += strlen(str);
      }
    } while (i < lline);
    isAsgn = true;
  }
}

//------------------------------------------------------------------------------

template<class T>
void ListParameter<T>::assignIntegerList(const char* line) {
  fprintf(stderr, "Error: '%s' has no assignIntegerList function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<int>::assignIntegerList(const char* line) {
  if (isActive()) assignList(line);
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<pair<int,int> >::assignIntegerList(const char* line) {
  if (isActive()) assignList(line);
}

//------------------------------------------------------------------------------

template<class T>
void ListParameter<T>::assignDoubleList(const char* line) {
  fprintf(stderr, "Error: '%s' has no assignDoubleList function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<double>::assignIntegerList(const char* line) {
  if (isActive()) assignList(line);
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<double>::assignDoubleList(const char* line) {
  if (isActive()) assignList(line);
}

//------------------------------------------------------------------------------

template<class T>
void ListParameter<T>::assignStringList(const char* line) {
  fprintf(stderr, "Error: '%s' has no assignStringList function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<string>::assignStringList(const char* line) {
  if (isActive()) assignList(line);
}

//------------------------------------------------------------------------------

template<class T>
inline
void ListParameter<T>::assignIntegerRange(const char* line) {
  fprintf(stderr, "Error: '%s' has no assignIntegerRange function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
void ListParameter<pair<int,int> >::assignIntegerRange(const char* line) {
  if (isActive()) assignList(line);
}

//------------------------------------------------------------------------------

template<class T>
vector<T> ListParameter<T>::getList() const {
  vector<T> v;
  for (size_t i=0; i<val.size(); ++i) v.push_back(val[i]);
  return v;
}

//------------------------------------------------------------------------------

template<class T>
vector<int> ListParameter<T>::getOneIntegerList() const {
  fprintf(stderr, "Error: '%s' has no getOneIntegerList function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
vector<int> ListParameter<int>::getOneIntegerList() const {
  return getList();
}

//------------------------------------------------------------------------------

template<class T>
vector<double> ListParameter<T>::getOneDoubleList() const {
  fprintf(stderr, "Error: '%s' has no getOneDoubleList function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
vector<double> ListParameter<double>::getOneDoubleList() const {
  return getList();
}

//------------------------------------------------------------------------------

template<class T>
vector<string> ListParameter<T>::getOneStringList() const {
  fprintf(stderr, "Error: '%s' has no getOneStringList function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
vector<string> ListParameter<string>::getOneStringList() const {
  return getList();
}

//------------------------------------------------------------------------------

template<class T>
vector<pair<int,int> > ListParameter<T>::getOneIntegerRange() const {
  fprintf(stderr, "Error: '%s' has no getOneIntegerRange function\n", getName());
  exit(1);
}

//------------------------------------------------------------------------------

template<>
inline
vector<pair<int,int> > ListParameter<pair<int,int> >::getOneIntegerRange() const {
  return getList();
}

//------------------------------------------------------------------------------

template<class T>
void ListParameter<T>::linedump(FILE* fp, const char* prefix) const {
  int size = val.size();
  fprintf(fp, "%s%s%s = [", prefix, isAsgn ? "" : "// ", getName());
  for (int i=0; i<size; ++i) {
    fprintf(fp, "%s%s", convertToString(val[i]).c_str(), i==size-1 ? "" : " ");
  }
  fprintf(fp, "];");
}
//------------------------------------------------------------------------------

template<class T>
void ListParameter<T>::linedump(ostream& out, const char* prefix) const {
  int size = val.size();

  out << prefix << getName() << " = [";
  // fprintf(fp, "%s%s%s = [", prefix, isAsgn ? "" : "// ", getName());
  for (int i=0; i<size; ++i) {
    out << convertToString(val[i]) << ((i==size-1) ? "" : " ");
    // fprintf(fp, "%s%s", convertToString(val[i]).c_str(), i==size-1 ? "" : " ");
  }
  out << "];";
  // fprintf(fp, "];");
}

//------------------------------------------------------------------------------

template<class T>
void ListParameter<T>::dump(FILE* fp, const char* prefix) const {
  linedump(fp, prefix);
  fprintf(fp, "\n");
}

//------------------------------------------------------------------------------

template<class T>
void ListParameter<T>::dumpAssigned(ostream& out, const char* prefix) const {
  if (isAssigned()) {
    linedump(out, prefix);
    out << "\n";
    // fprintf(fp, "\n");
  }
}

//------------------------------------------------------------------------------

template<class T>
bool ListParameter<T>::merge(Parameter* other) {
  ListParameter<T>* tmp = dynamic_cast<ListParameter<T> * >(other);
  return tmp;
}
  
//------------------------------------------------------------------------------
